#pragma once

#include<iostream>
#include<queue>
#include<pthread.h>
#include<ctime>
#include<unistd.h>

using namespace std;

template <class T>
class BlockQueue
{
    const static int defaultcapcacity=20;
public:
    BlockQueue(int maxcap=defaultcapcacity):_maxcap(maxcap)
    {
        pthread_mutex_init(&_mutex,nullptr);

        pthread_cond_init(&_p_cond,nullptr);
        pthread_cond_init(&_c_cond,nullptr);

        low_water=maxcap/3;
        high_water=(maxcap*2)/3;
    }
    //向任务队列中添加任务
    void push(const T data)
    {
        pthread_mutex_lock(&_mutex);

        while/*if*/(_queue.size()>=_maxcap)//不用if，而是用while，是为了防止出现伪唤醒情况
            pthread_cond_wait(&_p_cond,&_mutex);//队列里面没有空余位置了，生产者休眠等待

        usleep(10);//使被唤醒的生产线程微微停顿一下，免得与消费线程抢占屏幕资源，从而导致输出数据错乱问题
        _queue.push(data);//入队列
        
        if(_queue.size()>=high_water)
            pthread_cond_signal(&_c_cond);//数据队列内有很多数据了，可以向消费者发个消息，提醒一下，可以消费了

        pthread_mutex_unlock(&_mutex);
    }
    T pop()
    {
        pthread_mutex_lock(&_mutex);

        while/*if*/(_queue.empty())//不用if，而是用while，是为了防止出现伪唤醒情况
            pthread_cond_wait(&_c_cond,&_mutex);//队列里面没有数据了，消费者休眠等待
        
        usleep(10);//使被唤醒的消费线程微微停顿一下，免得与生产线程抢占屏幕资源，从而导致输出数据错乱问题
        T ret=_queue.front();
        _queue.pop();//出队列

        if(_queue.size()<=low_water)
            pthread_cond_signal(&_p_cond);//队列里面出现很多空位了，提醒一下生产者，可以开工了

        pthread_mutex_unlock(&_mutex);
        return ret;
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);

        pthread_cond_destroy(&_p_cond);
        pthread_cond_destroy(&_c_cond);
    }
private:
    std::queue<T> _queue;//存放共享资源的队列
    int _maxcap;//给数据队列限定一个最大值，这个最大值由用户自己确定

    //互斥锁，解决多线程并发访问共享资源时，导致的数据不一致问题
    //在生成消费模型中，"多线程"可以指多生产者间互斥，也可以指多消费者间的互斥
    //即"多生产者"可能同时生产同一份数据资源，"多消费者"可能同时消费同一份数据资源
    pthread_mutex_t _mutex;//互斥锁，保证“生成者与生产者”、“消费者与消费者”、“生产者与消费者”间的互斥关系

    //条件变量，可以解决生产者和消费者之间的互斥问题，并保证其对同一份数据的访问具有一定的顺序性
    pthread_cond_t _p_cond; //条件变量,实现生产者间的同步问题
    pthread_cond_t _c_cond; //条件变量,实现消费者间的同步问题

    int low_water;
    int high_water;
};   